<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      canvas {
        position: fixed;
        left: 0;
        top: 0;
        background-color: #222;
      }
    </style>
  </head>
  <body>
    <canvas></canvas>
    <script>
      const cvs = document.querySelector("canvas");
      const ctx = cvs.getContext("2d");

      function init() {
        cvs.width = window.innerWidth;
        cvs.height = window.innerHeight;
      }

      init();

      //   获取随机数
      function getRandom(min, max) {
        return Math.floor(Math.random() * (max + 1 - min) + min);
      }
      // --------- 画圆 ---------
      class Point {
        constructor() {
          this.r = 6;
          this.x = getRandom(0, cvs.width - this.r / 2);
          this.y = getRandom(0, cvs.height - this.r / 2);
          this.xSpeed = getRandom(-50, 50);
          this.ySpeed = getRandom(-50, 50);
          this.lastDrawTime = null;
        }
        draw() {
          // 更新坐标
          if (this.lastDrawTime) {
            // 计算新的坐标
            const duration = (Date.now() - this.lastDrawTime) / 1000; // 时间差
            // 距离
            const xDis = this.xSpeed * duration,
              yDis = this.ySpeed * duration;
            // 新的坐标
            let x = this.x + xDis,
              y = this.y + yDis;
            // 边界处理
            if (x > cvs.width - this.r / 2) {
              x = cvs.width - this.r / 2;
              this.xSpeed = -this.xSpeed;
            } else if (x < 0) {
              x = 0;
              this.xSpeed = -this.xSpeed;
            }
            if (y > cvs.height - this.r / 2) {
              x = cvs.height - this.r / 2;
              this.ySpeed = -this.ySpeed;
            } else if (x < 0) {
              x = 0;
              this.ySpeed = -this.ySpeed;
            }
            // 更新坐标
            this.x = x;
            this.y = y;
          }
          ctx.beginPath();
          // 圆心XY坐标 , 半径 , 起始角度与结束角度 , true表示逆时针
          ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI, true);
          ctx.fillStyle = "rgb(200, 200, 200)";
          ctx.fill();
          this.lastDrawTime = Date.now();
        }
      }

      // --------- 画图(很多点连线成的图) ---------
      class Graph {
        constructor(pointNumber = 30, maxDis = 200) {
          this.points = new Array(pointNumber).fill(0).map(() => new Point());
          this.maxDis = maxDis;
        }
        draw() {
          requestAnimationFrame(() => {
            this.draw();
          });
          // 清空画布
          ctx.clearRect(0, 0, cvs.width, cvs.height);
          // 绘制30个原点
          for (let i = 0; i < this.points.length; i++) {
            const p1 = this.points[i];
            p1.draw();
            // 点与点之间连线
            for (let j = i + 1; j < this.points.length; j++) {
              const p2 = this.points[j];
              const d = Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
              if (d > this.maxDis) {
                continue;
              }
              ctx.beginPath();
              ctx.moveTo(p1.x, p1.y);
              ctx.lineTo(p2.x, p2.y);
              ctx.closePath();
              //   ctx.strokeStyle = rgb(200, 200, 200);
              // 线的颜色是根据距离动态计算的 , 越远就越透明
              ctx.strokeStyle = `rgba(200, 200, 200,${1 - d / this.maxDis})`;
              ctx.stroke();
            }
          }
        }
      }

      const g = new Graph();
      g.draw();
    </script>
  </body>
</html>
